<template>
  <div class="chart-main">
    <div ref="$chart"
         :style="{ height: height, width: width }" />
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
// 引入 echarts 核心模块，核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core'
// 引入图表，图表后缀都为 Chart
import { LineChart, BarChart, PieChart, RadarChart } from 'echarts/charts'
// 引入组件，组件后缀都为 Component
import {
  TitleComponent,
  TooltipComponent,
  ToolboxComponent,
  GridComponent,
  LegendComponent,
  VisualMapComponent,
} from 'echarts/components'
// 标签自动布局，全局过渡动画等特性
import { UniversalTransition, LabelLayout } from 'echarts/features'
// 引入 Canvas 渲染器，注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers'

const emit = defineEmits(['click'])
let chart = null //echarts实例 不可以是响应式对象 不然resize()方法会报错
const $chart = ref(null) //dom

// 注册必须的组件
echarts.use([
  // 线图
  LineChart,
  TitleComponent,
  TooltipComponent,
  GridComponent,
  UniversalTransition,
  CanvasRenderer,
  LegendComponent,
  ToolboxComponent,
  // 柱状图
  BarChart,
  //饼图
  PieChart,
  LabelLayout,
  //雷达图
  VisualMapComponent,
  RadarChart,
])

const props = defineProps({
  width: {
    type: String,
    default: '100%',
  },
  height: {
    type: String,
    default: '350px',
  },
  autoResize: {
    type: Boolean,
    default: true,
  },
  // 最关键的参数
  chartOption: {
    type: Object,
    required: true,
  },
  type: {
    type: String,
    default: 'canvas',
  },
})

function initChart() {
  chart = echarts.init($chart.value, null, {
    renderer: props.type,
  })
  // 注意第二个参数，是否不跟之前设置的 option 进行合并  为true即不合并 所有组件都会被删除，然后根据新 option 创建所有新组件。
  chart.setOption(props.chartOption, true)
  chart.on('click', handleClick)
}

function handleClick(params) {
  emit('click', params)
}

function setOptions(option) {
  clearChart()
  resizeHandler()
  if (chart) {
    chart.setOption(option, true)
  }
}

// 由于 更新option配置 是通过函数的返回对象重新赋值实现的，
//尽管props.chartOption是响应式对象 但整体替换时 并不能被直接监听
//所以通过下面这种方式 实现监听对象的整体替换
watch(
  () => props.chartOption,
  (newVal) => {
    setOptions(newVal)
  }
)

function clearChart() {
  chart && chart.clear()
}

function resizeHandler() {
  // 根据挂载元素的宽高 调整canvas的 width height 属性
  chart.resize()
}

onMounted(() => {
  initChart()
  if (props.autoResize) {
    // autoResize默认是true 改变图表尺寸，实例.resize()在容器大小发生改变时需要手动调用。//容器宽度100% 调整时宽度变化 canvas使用是必须写死width和height的
    //echarts可以通过计算目前挂载容器的宽高 给canvas设置宽高
    window.addEventListener('resize', resizeHandler)
  }
})

onBeforeUnmount(() => {
  if (!chart) {
    return
  }
  if (props.autoResize) {
    window.removeEventListener('resize', resizeHandler)
  }
  // 销毁实例
  chart.dispose()
  chart = null
})
</script>

<style lang="scss" scoped>
</style>